import { Injectable, Inject } from '@nestjs/common';
import * as Jwt from 'jsonwebtoken';
import { validateAndDecrypt } from '../decrypt/decrypt.utils';

export interface ZsyzTokenConfig {
    secret: string;
    expiresIn: string;
}

export interface TokenUser {
    id?: number | string;
    username?: string;
    type?: string;
    mobile?: string;
    isSuper?: boolean;
    openid?: string;
    unionid?: string;
    activityId?: string;
    [key: string]: any;
}

export interface TokenResult {
    token: string;
    expiresIn: number;
}

@Injectable()
export class ZsyzTokenService {
    private licenseCache: { isValid: boolean; lastCheck: number } = {
        isValid: true,
        lastCheck: 0
    };

    // 缓存检查间隔（5分钟）
    private readonly CACHE_INTERVAL = 5 * 60 * 1000;

    constructor(
        @Inject('ZSYZ_JWT_CONFIG')
        private readonly config: ZsyzTokenConfig
    ) { }

    /**
     * 检查许可证是否有效
     * @returns 许可证是否有效
     */
    private checkLicense(): boolean {
        const now = Date.now();

        // 如果缓存还有效，直接返回缓存结果
        if (now - this.licenseCache.lastCheck < this.CACHE_INTERVAL) {
            if (!this.licenseCache.isValid) {
                this.stopService();
                return false;
            }
            return true;
        }

        try {
            // 尝试验证许可证，如果过期会抛出异常
            const result = validateAndDecrypt();

            // 如果执行到这里，说明许可证有效
            this.licenseCache.isValid = true;
            this.licenseCache.lastCheck = now;
            return true;
        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);

            if (errorMessage.includes('许可证已过期')) {
                console.error('❌ 许可证已过期，服务将停止运行');
            } else {
                console.error('❌ 许可证验证失败:', errorMessage);
            }

            this.licenseCache.isValid = false;
            this.licenseCache.lastCheck = now;
            this.stopService();
            return false;
        }
    }

    /**
     * 停止服务
     */
    private stopService(): void {
        console.error('🛑 许可证验证失败，正在停止服务...');

        // 延迟退出，确保日志能够输出
        setTimeout(() => {
            process.exit(1);
        }, 1000);
    }

    /**
     * 生成token
     * @param user - 用户信息
     * @param expires - 可选的过期时间（字符串格式如 '7d' 或数字秒数）
     * @returns token结果
     */
    generateToken(user: TokenUser, expires?: string | number): TokenResult {
        if (!this.checkLicense()) {
            throw new Error('许可证验证失败，服务不可用');
        }

        const tokenUser = {
            username: user.username,
            id: user.id,
            type: user.type,
            mobile: user.mobile,
            isSuper: user.isSuper,
            openid: user.openid,
            unionid: user.unionid,
            activityId: user.activityId,
        };

        // 解析过期时间
        const expiresInSeconds = expires
            ? (typeof expires === 'string' ? this.parseExpiresIn(expires) : expires)
            : this.parseExpiresIn(this.config.expiresIn);

        const token = Jwt.sign(
            { user: tokenUser },
            this.config.secret,
            { algorithm: 'HS256', expiresIn: expiresInSeconds }
        );

        return {
            token,
            expiresIn: expiresInSeconds
        };
    }

    /**
     * 解析token
     * @param token - JWT token字符串
     * @returns 解析后的token数据
     */
    decodeToken(token: string): any {
        if (!this.checkLicense()) {
            throw new Error('许可证验证失败，服务不可用');
        }

        if (!token) return null;
        const regex = /((?:\.?(?:[A-Za-z0-9-_]+)){3})$/gm;
        const matchRes = token.match(regex);
        if (!matchRes) return null;
        token = matchRes[0];
        let result: any;
        Jwt.verify(
            token,
            this.config.secret,
            { ignoreExpiration: true },
            (err, decoded) => {
                if (!err) {
                    result = decoded;
                }
            }
        );
        return result;
    }

    /**
     * 验证token是否有效
     * @param token - JWT token字符串
     * @returns 是否有效
     */
    verifyToken(token: string): boolean {
        if (!this.checkLicense()) {
            throw new Error('许可证验证失败，服务不可用');
        }

        try {
            Jwt.verify(token, this.config.secret);
            return true;
        } catch (error) {
            return false;
        }
    }

    /**
     * 从token中获取用户信息
     * @param token - JWT token字符串
     * @returns 用户信息
     */
    getUserFromToken(token: string): TokenUser | null {
        if (!this.checkLicense()) {
            throw new Error('许可证验证失败，服务不可用');
        }

        const decoded = this.decodeToken(token);
        return decoded?.user || null;
    }

    /**
     * 手动检查许可证状态（用于外部调用）
     * @returns 许可证状态信息
     */
    getLicenseStatus(): { isValid: boolean; message: string; timeInfo?: any } {
        try {
            const result = validateAndDecrypt();

            // 如果执行到这里，说明许可证有效
            return {
                isValid: true,
                message: '许可证有效',
                timeInfo: result.timeInfo
            };
        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);

            if (errorMessage.includes('许可证已过期')) {
                return {
                    isValid: false,
                    message: '许可证已过期'
                };
            }

            return {
                isValid: false,
                message: `许可证验证失败: ${errorMessage}`
            };
        }
    }

    /**
     * 解析过期时间字符串为秒数
     * @param expiresIn - 过期时间字符串
     * @returns 秒数
     */
    private parseExpiresIn(expiresIn: string): number {
        const match = expiresIn.match(/^(\d+)([smhd])$/);
        if (!match) return 864000; // 默认10天

        const [, value, unit] = match;
        const num = parseInt(value, 10);

        switch (unit) {
            case 's': return num;
            case 'm': return num * 60;
            case 'h': return num * 3600;
            case 'd': return num * 86400;
            default: return 864000;
        }
    }
} 